<?php

/**
 * CCore
 * CCoreException
 *
 * @author Usenko Timur <usenko.timur@gmail.com>
 * @package core
 */

/**
 * @final
 * @package core
 */
final class CCore
{
	#<editor-fold defaultstate="collapsed" desc="construct (private)">
	private function __construct() {}
	#</editor-fold>

	/**
	 * @staticvar array $aPackages
	 * @param string $sPackageToUse
	 * @param bool $bReturn = false
	 * @return bool
	 */
	public static function Using($sPackageToUse, $bReturn = false)
	{
		static $aPackages = array();
		if (isset($aPackages[$sPackageToUse]))
		{
			return true;
		}

		if (preg_match('/^[a-z0-9\.]+$/', $sPackageToUse))
		{
			$sClassFile = preg_replace('/[\.]+/', '.', $sPackageToUse);
			$sClassFile = self::RootPath().str_replace('.', DIRECTORY_SEPARATOR, $sClassFile).'.php';
			if (file_exists($sClassFile))
			{
				$aPackages[$sPackageToUse] = true;
				return ($bReturn) ? include($sClassFile) : (bool) include($sClassFile);

			}
			else
			{
				self::_usingFunctionError(@debug_backtrace(), 'package "'.$sPackageToUse.'" dosn\'t exist.');
			}
		}

		self::_usingFunctionError(@debug_backtrace(), 'package "'.$sPackageToUse.'" not valid.');
		return false;
	}

	/**
	 * @staticvar string $sRootPath
	 * @return string
	 */
	public static function RootPath()
	{
		static $sRootPath = null;
		if (null === $sRootPath)
		{
			$sRootPath = realpath(dirname(__FILE__)).DIRECTORY_SEPARATOR;
		}
		return $sRootPath;
	}

	/**
	 * @staticvar string $sVersion
	 * @return string
	 */
	public static function Version()
	{
		static $sVersion = null;
		if (null === $sVersion)
		{
			$sVersion = @file_get_contents(self::RootPath().'.VERSION');
		}
		return $sVersion;
	}

	/**
	 * @param array	$aInputsNames
	 * @return bool
	 */
	public static function CheckTypes($aInputsNames)
	{
		return true;

		$aStack = @debug_backtrace();
		if (!isset($aStack[1], $aStack[1]['args']) || !is_array($aStack[1]['args']))
		{
			return false;
		}

		foreach ($aInputsNames as $iKey => $aInputsName)
		{
			if ('*' !== $aInputsName && key_exists($iKey, $aStack[1]['args']))
			{
				$sInputType = self::_getTypeFromName($aInputsName);
				$sTraceType = gettype($aStack[1]['args'][$iKey]);
				if ($sInputType !== 'other' && $sInputType !== 'mixed' && strtolower($sTraceType) !== $sInputType)
				{
					if (('n' === substr($aInputsName, 1, 1)) && strtolower($sTraceType) === 'null')
					{
						continue;
					}

					throw new CCoreException('Argument '.$aInputsName.' passed to '.
						$aStack[1]['class'].$aStack[1]['type'].$aStack[1]['function'].'() '.
						'must be "'.$sInputType.'", '.$sTraceType.' given.',
						$aStack[1]['file'], $aStack[1]['line']);
				}
				else if ('other' === $sInputType)
				{
					throw new CCoreException('Argument '.$aInputsName.' passed to '.
						$aStack[1]['class'].$aStack[1]['type'].$aStack[1]['function'].'() '.
						'must be standart, '.$sTraceType.' given.',
						$aStack[1]['file'], $aStack[1]['line']);
				}
			}
		}

		return true;
	}

	/**
	 * @return void
	 */
	static public function Init()
	{
		ini_set('display_errors', 1);
		error_reporting(E_ALL & ~E_STRICT);

		self::_setTimeZone();

		define('CORE_START', microtime(true));
	}

	/**
	 * @staticvar bool $bIsTimeZoneSet
	 * 
	 * @param string $sTimeZone = null
	 * @return void
	 */
	private static function _setTimeZone($nsTimeZone = null)
	{
		static $bIsTimeZoneSet = false;
		if (!$bIsTimeZoneSet && function_exists('date_default_timezone_set'))
		{
			if (null === $nsTimeZone)
			{
				$nsTimeZone = function_exists('date_default_timezone_get') ? @date_default_timezone_get() : 'US/Pacific';
			}
			if ($nsTimeZone && strlen($nsTimeZone) > 0)
			{
				@date_default_timezone_set($nsTimeZone);
			}

			$bIsTimeZoneSet = true;
		}
	}

	/**
	 * @param string $aDebugBacktrace
	 * @param string $sErrorDesc
	 * @return void
	 */
	private static function _usingFunctionError($aDebugBacktrace, $sErrorDesc)
	{
		throw new CCoreException($sErrorDesc,
			(isset($aDebugBacktrace[1]['file'])) ? $aDebugBacktrace[1]['file'] : '',
			(isset($aDebugBacktrace[1]['line'])) ? $aDebugBacktrace[1]['line'] : 0);
	}

	/**
	 * @param string $sName
	 * @return string
	 */
	private static function _getTypeFromName($sName)
	{
		$sType = ('n' === substr($sName, 1, 1)) ? substr($sName, 2, 1) :  substr($sName, 1, 1);
		switch ($sType)
		{
			case 's':	return 'string';
			case 'i':	return 'integer';
			case 'a':	return 'array';
			case 'b':	return 'boolean';
			case 'o':	return 'object';
			case 'm':	return 'mixed';
			default:	return 'other';
		}
	}
}

/**
 * @package core
 */
class CCoreException extends ErrorException
{
	/**
	 * @param string $sMessage
	 * @param string $sFileName
	 * @param int $iFileLine
	 * @return CCoreException
	 */
	public function __construct($sMessage, $sFileName, $iFileLine)
	{
		parent::__construct($sMessage, 0, 0, $sFileName, $iFileLine);
	}

	/**
	 * @return void
	 */
	public function __toString()
	{
		$sFile = $this->getFile();
		$sLine = $this->getLine();
		$sFile = strlen($sFile) > 0 ? '<br />in '.$sFile : '';
		$sLine = (strlen($sFile) > 0 && $sLine > 0) ? ' ('.$sLine.')' : '';
		exit('<html><body style="font: normal 13px tahoma, arial; color: black; background: #ccc;">
<div style="border: solid 1px #5b86a8; margin: 5px; padding: 5px; background: #ffffe1;">
<font color="red"><b>CoreProject:</b></font><ul>'.
$this->getMessage().$sFile.$sLine.'<br /><br />'.nl2br($this->getTraceAsString()).
'</ul></div></body></html>');
	}
}

CCore::Init();
